/*
 * msgdsp.c
 * 
 * Copyright 2012 Kamil Cukrowski <kamil@dyzio.pl>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation version 2.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 */
#define MSGDSP_VERSION "1.0.2"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include <syslog.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include "msgserv.h"

# define MY_NAME "msgdsp"
#define REFRESH 2
#define min(x,y) ((x) < (y) ? (x) : (y))
#define LCD_ROWS LCD_ROW
#define PDEBUG(arg, ...) if(debug) { printf(arg, ##__VA_ARGS__); };


#define PINFO(smt, ...) do { printf(smt, ## __VA_ARGS__ ); printf("\n"); } while(0)
#define PDEBUG(str, ...) PDEBUGL(1, str, ##__VA_ARGS__);
#define PDEBUGL(x, str, ...) do{ if ( debug >= x ) _INTERNAL_LOGIT(str, ##__VA_ARGS__); }while(0)
#define PERROR(str, ...) do { printf(MY_NAME ": (%s:%d): ", __FILE__, __LINE__); printf(str, ##__VA_ARGS__); printf("error %d:%s \n", errno, strerror(errno)); }while(0)
#define _INTERNAL_LOGIT(str, ...) do { printf( MY_NAME ": (%s:%d): ", __FILE__, __LINE__); printf(str, ##__VA_ARGS__); printf("\n"); }while(0)



int messages=0;                   //number of messages stored at the server
struct message_t message[MAX_MESG]={[0 ... MAX_MESG-1]={0,{},0,0,0,{[0 ... MSG_LEN]=0}}};


# define dsp_baner()
int on_display[2][MAX_MESG];
int mini=0;
# include "ncurses.c"

#define _error_mesg(mesg) if (debug) syslog(LOG_ERR,mesg); else fprintf(stderr,mesg);
  

#define emerg_clean(mesg) \
	if (debug)\
		puts(mesg);\
	else\
		_error_mesg(mesg);\
	close(sockfd);\
	messages=0;\
	dsp_shift();\
	dsp_refresh()

in_addr_t server_ip;
int sockfd;
int sin_size = sizeof(struct sockaddr_in);
int PID;
#define buff_len 256
char buff[buff_len];
int active_messages;
int active_message[MAX_MESG];
int debug=0;
int clients=0;
struct in_addr client[MAX_CLIENT];
enum
{
	MODE_NORMAL,
	MODE_MENU_FILTER,
	MODE_MENU_SCROL,
	MODE_MAX
};
unsigned int dsp_mode=MODE_NORMAL;

enum
{
	SCROL_AUTO,
	SCROL_MANUAL
};
int dsp_scrol=SCROL_AUTO;
void parse_config(char *config_file)
{
   FILE *fd;
   int i;
   if ( (fd=fopen(config_file,"r")) != NULL ) {
      while ( fgets(buff,buff_len,fd) != NULL ) {
	 if ( memcmp(buff,"SERVER_IP=",10) == 0 ) {
	    server_ip=inet_addr(buff+10);
	    if ( debug ) {
	       puts("Faund:");
	       puts(buff);
	    }
	 }
	 else if ( memcmp(buff,"LCD_CLIENTS=",12) == 0 ) {
	    if ( debug ) {
	       puts("Faund:");
	       puts(buff);
	    }
	    i=12;
	    while ( buff[i] != 0 ) {
	       client[clients++].s_addr=inet_addr(buff+i);
	       while ( ( buff[++i] != 0 ) && ( buff[i] != ' ' ) );
	       while ( buff[i] == ' ' ) i++;
	    }
	 }
      }
   }
}

void parse_cmd(int argc, char *argv[])
{
   int c=0;
   extern char *optarg;
   while (c != -1) {
      c=getopt(argc, argv, "hdi:c:C");
      switch (c) {
       case 'h':
         printf(MY_NAME
		": messaging system to LCD geteway.\n"
                "\t-h\tdisplay this help.\n"
                "\t-d\tdebug monde on (do not fork into the background);\n"
                "\t-i<IP address>\t server ip address.\n"
		"\t-c<IP address>\t address of the client which messages\n"
		"\t\tshould be displayed, may be specyfied multiple times\n"
		"\t-C\treset client list\n");
	 exit(0);
       case 'd':
         debug=1;
         break;
       case 'i':
         server_ip=inet_addr(optarg);
         break;
       case 'c':
	 if ( clients == MAX_CLIENT ) {
	    fprintf(stderr,"Too many clients give");
	    exit(1);
	 }
	 else
	   client[clients++].s_addr=inet_addr(optarg);
	 break;
       case 'C':
	 clients=0;
	 break;
      }
   }
}

void sig_hup ()
{
   msg_send(sockfd,"#EXIT",5);
   ok_test(sockfd);
   LCD_rst();
   dsp_baner();
   LCD_close();
   exit(0);
}


//----------------dsp-----------------

int active_msg,shift;

int dsp_rst()
{
	int i;
	active_msg=0;
	for (i=0;i<LCD_ROW;i++)
		on_display[0][i]=-1;
	return(LCD_rst());
}

int dsp_refresh()
{
	int i;
	for (i=0;i<LCD_ROW;i++) {
		if ( on_display[0][i]!=on_display[1][i] ) {
			if ( (on_display[0][i]=on_display[1][i]) == -1 ) {
				if (LCD_clr_line(i)<0)
					return(-1);
			} else {
				if ( dsp_message(on_display[0][i],i) < 0 )
					return(-1);
			}
		}
	}
	return(0);
}

void dsp_shift()
{
	int i,j,l,h;
	term_resize();
	if ( clients ) {
		active_messages=0;
		for ( i=0; i<messages; i++ ) {
			j=-1;
			while ( ( ++j < clients ) &&
				( memcmp(&(message[i].addr),&(client[j]), sizeof (struct in_addr) ) ) );
				if ( j < clients )
					active_message[active_messages++]=i;
		}
		if ( debug ) {
			for (i=0;i<active_messages;i++)
				printf("Active mesg #%d: %d.\n",i,active_message[i]);
		}
	} else {
		active_messages=messages;
	}
	if ( ( active_messages<=LCD_ROW ) ||
		( message[active_message[LCD_ROW-1]].pri < message[active_message[LCD_ROW]].pri ) ) {
		for (i=0;i<LCD_ROW;i++) {
			if ( i<active_messages )
				on_display[1][i]=active_message[i];
			else
				on_display[1][i]=-1;
		}
		active_msg=0;
	} else {
		if ( active_messages < LCD_ROW )
			l=active_messages;
		else
			l=LCD_ROW;
		h=l;
		while ( ( l>0 ) &&
			( message[active_message[l-1]].pri == message[active_message[l]].pri) )
			l--;
		while ( ( h<active_messages-1 ) &&
			( message[active_message[h+1]].pri == message[active_message[h]].pri) )
			h++;
		for (i=0;i<l;i++)
			on_display[1][i]=active_message[i];
		if ( ( active_msg < l ) || ( active_msg > h ) ) {
			active_msg=l;
		} else {
			if ( ++shift>=LCD_ROW-l )
				shift=0;
			if ( ++active_msg>h )
				active_msg=l;
		}
		j=active_msg;
		for (i=0;i<LCD_ROW-l;i++) {
			on_display[1][l+((i+shift)%(LCD_ROW-l))]=active_message[j];
			if ( ++j>h ) j=l;
		}
	}
}

//----------------dsp end------------------

//-----------------msg-------------------
int msg_find(int client, char nr)
{
   int i;
   i=-1;
   while ( (++i < messages) && ( ( message[i].client!=client ) || ( message[i].nr!=nr ) ) );
   return(i);
}

void msg_dump()
{
   int i,j;
   char *c;
   struct tm *time_rec;
   time_t tmp_time;
   if (messages==0)
     puts("Nothing to dump.");
   else {
      puts("Dumping messages");
      puts("+---+---+---------------|---+---+-----+----------------------------------------+\n"
           "|msg|cli|   IP address  |nr |pri|time |              text                      |\n"
           "+---+---+---------------|---+---+-----+----------------------------------------+");
      for (i=0;i<messages;i++) {
         tmp_time=(time_t) message[i].time;
         time_rec=localtime(&tmp_time);
         printf("|%3d|%3d|",
                i,message[i].client);
         for (j=15-strlen((c=inet_ntoa(message[i].addr)));j>0;j--)
           putc(' ',stdout);
         printf("%s",c);
         printf("|%3d|%3d|%.2d:%.2d|", message[i].nr, message[i].pri, (*time_rec).tm_hour,(*time_rec).tm_min);
         for (j=0;j<MSG_LEN;j++) {
            if ( message[i].mesg[j]<8 )
              putchar(message[i].mesg[j]+'0');
            else
              putchar(message[i].mesg[j]);
         }
         puts("|");
      }
      puts("+---+---+---------------|---+---+-----+----------------------------------------+");
      for (i=0;i<active_messages;i++)
	printf("Active mesg #%d: %d.\n",i,active_message[i]);
      puts("Dumping display\n"
	   "+---+---+----------------------------------------+\n"
	   "|row|msg|                 text                   |\n"
	   "+---+---+----------------------------------------+");
      for (i=0;i<LCD_ROW;i++) {
	 if (i<active_messages) {
	    printf("|%3d|%3d|",i,on_display[0][i]);
	    for (j=0;j<MSG_LEN;j++) {
	       if ( message[on_display[0][i]].mesg[j]<8 )
		 putchar(message[on_display[0][i]].mesg[j]+'0');
	       else
		 putchar(message[on_display[0][i]].mesg[j]);
	    }
	    puts("|");
	 }
	 else
	   puts("|   |   |                                        |");
      }
      puts("+---+---+----------------------------------------+");
   }
}

int msg_shift(int mesg, int direct)
{
   int i;
   if ( (mesg<0) || (mesg>=messages) )
     return(-1);
   memcpy(&(message[mesg+direct]),&(message[mesg]),sizeof (struct message_t));
   i=LCD_ROW;
   while ( ( --i>=0 ) && 
	   ( on_display[0][i] != mesg ) );
   if (i>=0)
     on_display[0][i]=on_display[0][i]+direct;
   return(0);
}

int  msg_delete(int mesg)
{
	int i;
	if ( (mesg < 0) || (mesg > messages) )  {
		printf("\n");
		return(-1);
	}
	messages--;
	for (i=0;i<LCD_ROW;i++) {
		if ( on_display[0][i] > mesg ) {
			on_display[0][i]--;
		} else if ( on_display[0][i] == mesg ) {
			if(debug) printf("cleaning line %d.\n",i);
			LCD_clr_line(i);
			on_display[0][i] = -1;
		}
	}
	for(i = mesg; i < messages; i++) {
		memcpy(&(message[i]), &(message[i+1]), sizeof(*message));
	}
	return(0);
}

#define reorder_test(mesg_a,mesg_b) ( ( mesg_a.pri>mesg_b.pri ) || \
	 ( ( mesg_a.pri==mesg_b.pri ) && ( mesg_a.client>mesg_b.client ) ) || \
	 ( ( mesg_a.pri==mesg_b.pri ) && ( mesg_a.client==mesg_b.client ) && ( mesg_a.nr>mesg_b.nr ) ) )

/* if messege has MSG_FORWARD, print it to lcds and return 2 */
int msg_bypass_all(char *buff)
{
	struct message_t temp;
	memcpy( &(temp), buff+3, sizeof (struct message_t) );
	if ( temp.pri == MSG_FORWARD ) {
		return (2);
	}
	return (0);
		
}

int msg_add_new_message(char *buff) {
	int i;
	i = messages;
	if (messages == MAX_MESG) {
		if (debug) printf("Too many messages.");
		return(-1);
	} else {
		messages++;
	}
	if ( ( i<messages-1 ) && ( reorder_test( (*((struct message_t *) &(buff[3]))), message[i+1] ) ) ) {
		do {
			i++;
			msg_shift(i, -1);
		} while ( ( i<messages-1 ) && ( reorder_test( (*((struct message_t *) &(buff[3]))), message[i+1] ) ) );
	} else if ( ( i>0 ) && ( reorder_test( message[i-1], (*((struct message_t *) &(buff[3]))) ) ) ) {
		do {
			i--;
			msg_shift(i, +1);
		} while ( ( i>0 ) && ( reorder_test ( message[i-1],(*((struct message_t *) &(buff[3]))) ) ) );
	}
	return i;
}
		
int msg_meng(char *buff, int len)
{
	int i,j;
	if ( (buff[0]!='#') || (buff[2]!='#') ) {
		if (debug) printf("Parser error. \n");
		return(-1);
	}
	switch (buff[1]) {
	case MSG_UP:
		switch ( len ) {
		case 3 + sizeof (struct message_t):
			i = msg_find((*((struct message_t *) &(buff[3]))).client,
				(*((struct message_t *) &(buff[3]))).nr);
			if ( debug ) {
				if ( i == messages ) printf("Adding: \n");
				else printf("Updating: \n");
			}
			if (i == messages) {
				i = msg_add_new_message(buff);
				if ( i < 0 ) return(-3);
				
			}
			memcpy(&(message[i]),buff+3,sizeof (struct message_t));
			for(j = LCD_ROW-1; ( j >= 0 ) && ( on_display[0][j] != i ) ; j-- );
			if (j > -1) {
				on_display[0][j] = i;
				dsp_message(i, j);
			}
			break;
		case 3 + sizeof (struct message_t) - MSG_LEN:
			if ( (i=msg_find((*((struct message_t *) &(buff[3]))).client,
				(*((struct message_t *) &(buff[3]))).nr) ) == messages ) {
				if (debug) printf("Message not found.");
				return(-1);
			}
			if (debug) printf("Deleting mesg # %d\n",i);
			msg_delete(i);
			break;
		default:
			if (debug) printf("invalid lenght. \n");
			return(-1);
		}
		break;
	case MSG_DEL:
		if ( len != 7 ) {
			if (debug) printf("invalid lenght. \n");
			return(-1);
		}
		if (debug) printf("Deletting messages from client %d\n",*( (int *) &(buff[3])));
		i = 0;
		while (i < messages) {
			if ( message[i].client == *( (int *) &(buff[3])) ) {
				msg_delete(i);
			} else {
				i++;
			}
		}
		break;
	default:
		if (debug) {
			puts("unknown packet");
		} else {
			syslog(LOG_INFO,"Unknown packet received.");
		}	
		return(-1);
		break;
	}
	return(0);
}
//----------------------msg end---------------------

//----------------------menu begin------------------

#define menu_scrol_len 3
char menu_scrol[][MSG_LEN+1]=
{
     "  " MY_NAME " " VER ":   Scrolling type          ",
     "  Auto                                  ",
     "  Manual                                "
};

#define menu_filter_len 3
char menu_filter[menu_filter_len+MAX_MESG+1][MSG_LEN+1]=
{
     "  " MY_NAME " " VER ":   Client filter config    ",
     "  Reset                                 ",
     "  Add unlisted ip                       "
};

char menu_selected[MAX_MESG];
int menu_active,menu_shift;
int menu_tmp_1;
#define _menu_active(row) \
   LCD_print_xy(0,row,">",1); \
   LCD_print_xy(MSG_LEN-1,row,"<",1)

#define _menu_inactive(row) \
   LCD_print_xy(0,row," ",1); \
   LCD_print_xy(MSG_LEN-1,row," ",1)

#define _menu_select(row) \
   LCD_print_xy(1,row,"*",1); \
   LCD_print_xy(MSG_LEN-2,row,"*",1)

#define _menu_unselect(row) \
   LCD_print_xy(1,row," ",1); \
   LCD_print_xy(MSG_LEN-2,row," ",1)


void menu_show( char menu[][MSG_LEN+1], int len,
		int shift, int active, char *selected )
{
   int i,j;
   LCD_rst();
   j=min( LCD_ROWS+shift, len );
   for ( i = shift; i < j; i++ ) {
      LCD_print_xy(0,i-shift,menu[i],MSG_LEN);
      if ( ( selected != NULL ) &&
	   ( selected[i] ) ) {
	 _menu_select(i-shift);
      }
   }
   _menu_active(active-shift);
}

void menu_mng ( int key )
{
   int i,j;
   in_addr_t addr_tmp;
   switch (dsp_mode) {
      
    case MODE_NORMAL:
      if ( key == 'F' ) {
	 dsp_mode = MODE_MENU_SCROL;
	 menu_active = menu_shift = 0;
	 bzero(menu_selected,menu_scrol_len);
	 menu_selected[dsp_scrol+1]=1;
	 menu_show( menu_scrol, menu_scrol_len, 
		    menu_shift, menu_active,menu_selected);
	 for (i=0;i<LCD_ROW;i++)
	   on_display[0][i]=-1;
      }
      break;
      
    case MODE_MENU_SCROL:
      switch ( key ) {
       case 'F':
	 switch ( menu_active ) {
	  case 0:
	    dsp_mode = MODE_NORMAL;
	    LCD_rst();
	    break;
	  case 1:
	  case 2:
	    if ( dsp_scrol == menu_active + 1 )
	      break;
#define displayed_test(row) \
   ( menu_shift <= row ) && \
     ( row < menu_shift + LCD_ROWS )
	    
	    if ( displayed_test( dsp_scrol + 1 ) ) {
	       _menu_unselect( dsp_scrol + 1 - menu_shift );
	    }
	    _menu_select(menu_active-menu_shift);
	    menu_selected[dsp_scrol+1]=0;
	    dsp_scrol=1-dsp_scrol;
	    menu_selected[dsp_scrol+1]=1;
	    break;
	 }
	 break;
	 
       case 'L':
       case 'R':
	 dsp_mode = MODE_MENU_FILTER;
	 menu_active = menu_shift = 0;
	 for (i=0;i<clients;i++) {
	    snprintf( menu_filter[menu_filter_len+i], MSG_LEN,
		     "  %.3d.%.3d.%.3d.%.3d                       ",
		     (client[i].s_addr & 255),
		     (client[i].s_addr >> 8 ) & 255,
		     (client[i].s_addr >> 16 ) & 255,
		     (client[i].s_addr >> 24 ) & 255);
	 }
	 menu_tmp_1=clients;
	 for (i=0;i<messages;i++) {
	    j=-1;
	    while ( ( ++j < menu_tmp_1 ) &&
		    ( message[i].addr.s_addr != client[j].s_addr ) );
	    if ( j == menu_tmp_1 ) {
	       snprintf( menu_filter[menu_filter_len+menu_tmp_1], MSG_LEN,
			 "  %.3d.%.3d.%.3d.%.3d                       ",
			 (message[i].addr.s_addr & 255),
			 (message[i].addr.s_addr >> 8 ) & 255,
			 (message[i].addr.s_addr >> 16 ) & 255,
			 (message[i].addr.s_addr >> 24 ) & 255);
	       client[menu_tmp_1++].s_addr = message[i].addr.s_addr;
	       if ( menu_tmp_1 == MAX_MESG )
		 break;
	    }
	 }
	 bzero(menu_selected,menu_filter_len+menu_tmp_1);
	 for( i=menu_filter_len; i<menu_filter_len+clients; i++ )
	   menu_selected[i]=1;
	 menu_show( menu_filter, menu_filter_len+menu_tmp_1, 
		    menu_shift, menu_active, menu_selected );
	 break;
	 
#define menu_up(menu,len,select); \
	 if ( ( LCD_ROWS >= len ) || \
	      ( menu_shift < menu_active ) ) { \
	    _menu_inactive(menu_active-menu_shift); \
	    if ( --menu_active < 0 ) \
	      menu_active = len - 1; \
	    _menu_active(menu_active-menu_shift); \
	 } \
	 else { \
	    if ( --menu_active >= 0 ) { \
	       menu_shift--; \
	    } \
	    else { \
	       menu_active = len - 1; \
	       menu_shift = len - LCD_ROWS; \
	    } \
	    menu_show( menu, len, \
		       menu_shift, menu_active, select); \
	 }
#define menu_down(menu,len,select); \
	 if ( ( LCD_ROWS >= len ) || \
	      ( menu_shift + LCD_ROWS > menu_active + 1 ) ) { \
	    _menu_inactive(menu_active-menu_shift); \
	    if ( ++menu_active == len ) \
	      menu_active = 0; \
	    _menu_active(menu_active-menu_shift); \
	 } \
	 else { \
	    if ( ++menu_active < len ) { \
	       menu_shift++; \
	    } \
	    else { \
	       menu_active = menu_shift = 0; \
	    } \
	    menu_show( menu, len, \
		       menu_shift, menu_active, select); \
	 }
	 
       case 'U':
	 menu_up(menu_scrol,menu_scrol_len,menu_selected);
	 break;
       case 'D':
	 menu_down(menu_scrol,menu_scrol_len,menu_selected);
	 break;
      }
      break;
      
    case MODE_MENU_FILTER:
      switch ( key ) {
       case 'F':
	 switch ( menu_active ) {
	  case 0:
	    dsp_mode = MODE_NORMAL;
	    LCD_rst();
	    break;
	  case 1:
	    if ( clients == 0 )
	      break;
	    clients=0;
	    bzero( menu_selected + menu_filter_len, menu_tmp_1);
	    menu_show( menu_filter, menu_filter_len+menu_tmp_1, 
		       menu_shift, menu_active, menu_selected );
	    for(i=0;i<MAX_MESG;i++)
	      active_message[i]=i;
	    break;
	  case 2:
	    break;
	  default:
	    if ( menu_active + 1 < clients + menu_filter_len ) {
	       // activ (but no the last activ) ip was selected
	       addr_tmp=client[--clients].s_addr;
	       client[clients].s_addr =
		 client[ menu_active - menu_filter_len ].s_addr;
	       client[ menu_active - menu_filter_len ].s_addr = addr_tmp;
	       memcpy(menu_filter[ menu_filter_len + MAX_MESG ],
		      menu_filter[ menu_filter_len + clients ], MSG_LEN+1 );
	       memcpy(menu_filter[ menu_filter_len + clients ],
		      menu_filter[ menu_active ], MSG_LEN+1 );
	       memcpy(menu_filter[ menu_active ],
		      menu_filter[ menu_filter_len + MAX_MESG ], MSG_LEN+1 );
	       menu_selected[ menu_filter_len + clients ] = 0 ;
	       menu_show( menu_filter, menu_filter_len+menu_tmp_1, 
		       menu_shift, menu_active, menu_selected );
	    }
	    else if ( menu_active + 1 == clients + menu_filter_len ) {
	       // last active selected
	       _menu_unselect( menu_active - menu_shift );
	       menu_selected[menu_active]=0;
	       if ( --clients == 0 )
		 for(i=0;i<MAX_MESG;i++)
		   active_message[i]=i;
	    }
	    else if ( menu_active  == clients + menu_filter_len ) {
	       // first unselected
	       _menu_select( menu_active - menu_shift );
	       menu_selected[menu_active]=1;
	       clients++;
	    }
	    else if ( menu_active > clients + menu_filter_len ) {
	       // inactiv (but no the forst inactiv) ip was selected
	       addr_tmp=client[clients].s_addr;
	       client[clients].s_addr =
		 client[ menu_active - menu_filter_len ].s_addr;
	       client[ menu_active - menu_filter_len ].s_addr = addr_tmp;
	       memcpy(menu_filter[ menu_filter_len + MAX_MESG ],
		      menu_filter[ menu_filter_len + clients ], MSG_LEN+1 );
	       memcpy(menu_filter[ menu_filter_len + clients ],
		      menu_filter[ menu_active ], MSG_LEN+1 );
	       memcpy(menu_filter[ menu_active ],
		      menu_filter[ menu_filter_len + MAX_MESG ], MSG_LEN+1 );
	       menu_selected[ menu_filter_len + clients ] = 1 ;
	       menu_show( menu_filter, menu_filter_len+menu_tmp_1, 
		       menu_shift, menu_active, menu_selected );
	       clients++;
	    }
//	    if ( menu_active + 1 < menu_filter_len + menu_tmp_1 ) {
//	       menu_down(menu_filter,menu_filter_len+menu_tmp_1,menu_selected);
//	    }
	    break;
	 }
	 break;
       case 'L':
       case 'R':
	 dsp_mode = MODE_MENU_SCROL;
	 menu_active = menu_shift = 0;
	 bzero(menu_selected,menu_scrol_len);
	 menu_selected[dsp_scrol+1]=1;
	 menu_show( menu_scrol, menu_scrol_len, 
		    menu_shift, menu_active,menu_selected);
	 break;
       case 'U':
	 menu_up(menu_filter,menu_filter_len+menu_tmp_1,menu_selected);
	 break;
       case 'D':
	 menu_down(menu_filter,menu_filter_len+menu_tmp_1,menu_selected);
	 break;
      }
      break;
   }
}

void reconnecting_on_error() 
{
	int i = 0;
	dsp_baner();
	for (i = 0; ( sockfd=lcd_socket_connect(server_ip)) < 0; i++ ) {
		if ( i > 10 ) {
			if (debug) {
				exit_("Could not reconnect");
			} else {	
				_error_mesg("Could not to reconnect");
				exit(errno);
				}
		}
		if (debug)
			puts("Reconnection failed. Still trying.");
		sleep(30);
	}
}



//---------------------menu end----------------------

int main(int argc, char *argv[])
{
	char buff[256];
	int i;
	struct timeval timeout;
	fd_set set;
	printf("-1\n");
	for (i=0;i<MAX_MESG;i++)
		active_message[i]=i;
	server_ip=inet_addr("127.0.0.1");
	parse_config(CONFIG_FILE);
	parse_cmd(argc,argv);
	printf("0\n");
	signal(SIGHUP, sig_hup);
	signal(SIGQUIT,sig_hup);
	signal(SIGTERM,sig_hup);
	signal(SIGINT,sig_hup);
	printf("1\n");
	if ( ( LCD_init() < 0 ) ) exit_("LCD INIT");
	printf("1.1\n");
	if (	( dsp_rst() < 0 ) ) exit_("LCD init");
	printf("2\n");
	dsp_baner();
	printf("3\n");
	time_t time_old=0,time_new;
	if ( ( sockfd=lcd_socket_connect(server_ip)) == -1 )
		exit_("bind");
	printf("3.1\n");
	if (sockfd == -2 ) {
		i=0;
		while ( ( sockfd = lcd_socket_connect(server_ip) ) < 0 ) {
			if ( ++i > 10 ) {
				if (debug) {
					exit_("Could not connect");
				} else {
					syslog(LOG_ERR,"Could not to connect");
					exit(errno);
				}
			}
			if (debug)
				puts("Connection failed. Still trying.");
			sleep(30);
		}
	}
	LCD_rst();
	
	while ( 1 ) {
	
		timeout.tv_sec=1;
		timeout.tv_usec=0;
		FD_ZERO(&set);
		FD_SET(sockfd,&set);
		FD_SET(0,&set);
	
		if ( select(sockfd+1,&set,NULL,NULL,&timeout) < 0 ) {	// this is "smart sleep"
			emerg_clean("Select error.");
			reconnecting_on_error();
		}
	
		if ( FD_ISSET(0,&set) ) {
			switch ( getch() ) {
			case 'q':
				sig_hup();
				break;
			case '\r':
			case ' ':
				menu_mng('F');
				break;
			case KEY_UP:
				menu_mng('U');
				break;
			case KEY_DOWN:
				menu_mng('D');
				break;
			case KEY_LEFT:
				menu_mng('L');
				break;
			case KEY_RIGHT:
				menu_mng('R');
				break;
			}
		}
	
		if ( FD_ISSET(sockfd,&set) ) {
			i = msg_recv(sockfd,(unsigned char *) buff,256);	
			if ( i < 0 )  {
				emerg_clean("Transmision error.");
				reconnecting_on_error();
			}
		} else {
				i=0;
		}
		if ( i > 0 ) {
			if ( msg_parity(buff,i) < 0 ) {
				emerg_clean("Parity error.");
				reconnecting_on_error();
			}
			if ( strncmp(buff+2,"#EXIT",5) == 0 ) {
				emerg_clean("Server closed the connection.");
				reconnecting_on_error();
			}
			if ( msg_bypass_all(buff+2) == 2 ) {
				if ( msg_send(sockfd,"#OK",3) < 0 ) {
					emerg_clean("error sending the replay");
					reconnecting_on_error();
				}
				continue;
			}
			if ( msg_meng(buff+2,i-4) < 0 ) {
				emerg_clean("Error processing of the request.");
				reconnecting_on_error();
			}
			if ( msg_send(sockfd,"#OK",3) < 0 ) {
				emerg_clean("error sending the replay");
				reconnecting_on_error();
			}
		}

		if ( ( dsp_mode == MODE_NORMAL ) && ( abs( ( time_new=time(NULL) ) - time_old ) >= REFRESH ) ) {
			time_old=time_new;
			dsp_shift();
			dsp_refresh();
			if (debug)
				msg_dump();
		}
		refresh();
	}
	return(0);
}

